package com.zdxlz.fcmp.common.security.filter;

import cn.hutool.core.util.StrUtil;
import com.zdxlz.fcmp.common.core.constant.CommonConstants;
import com.zdxlz.fcmp.common.core.constant.enums.ResCode;
import com.zdxlz.fcmp.common.core.util.CommonUtil;
import com.zdxlz.fcmp.common.core.util.HmacUtil;
import com.zdxlz.fcmp.common.core.util.R;
import com.zdxlz.fcmp.common.security.util.CachedBodyHttpServletRequest;
import com.zdxlz.fcmp.common.security.util.RequestUtil;
import com.zdxlz.fcmp.common.security.util.ResponseUtil;
import com.zdxlz.fcmp.upms.api.entity.ExternalPlatformConfig;
import com.zdxlz.fcmp.upms.api.service.IExternalPlatformConfigService;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.HttpMethod;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Map;

/**
 * @author: aman
 * @className IctHmacAuthenticationFilter
 * @date 2025/2/10 10:24
 * @description
 */
@Component
@AllArgsConstructor
@Slf4j
public class IctHmacAuthenticationFilter extends OncePerRequestFilter {

    private static final long TIME_LIMIT = 5 * 60 * 1000; // 5分钟的毫秒值


    @Qualifier("ictRequestMatcher")
    private final RequestMatcher ictRequestMatcher;
    private IExternalPlatformConfigService externalPlatformConfigService;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String appId = request.getHeader(CommonConstants.ICT_HEADER_APPID);
        String timestamp = request.getHeader(CommonConstants.ICT_HEADER_TIMESTAMP);
        String signture = request.getHeader(CommonConstants.ICT_HEADER_SIGNATURE);

        ExternalPlatformConfig ictPlatformConfig = preCheck(appId, timestamp, signture, response);
        if (null == ictPlatformConfig) {
            return;
        }

        String ictSecret = ictPlatformConfig.getAppSecret();
        CachedBodyHttpServletRequest cachedBodyHttpServletRequest = new CachedBodyHttpServletRequest(request);

        String method = cachedBodyHttpServletRequest.getMethod();
        String queryStr = "";
        String bodyStr = "";
        if (HttpMethod.GET.name().equals(method)) {
            Map<String, String> parameterMap = RequestUtil.readGetParameter(cachedBodyHttpServletRequest);
            String str = CommonUtil.mapSortToString(parameterMap);
            log.info("GET请求encode之前原始数据：{}",str);
            queryStr = URLEncoder.encode(str, StandardCharsets.UTF_8);

        }
        if (HttpMethod.POST.name().equals(method)) {
            bodyStr = CommonUtil.jsonToSortedJson(RequestUtil.readPostBody(cachedBodyHttpServletRequest));
        }

        String data = appId + timestamp + queryStr + bodyStr;
        log.info("签名验证原始数据：{}", data);
        String sign = HmacUtil.generateHmacSha256(data, ictSecret);

        if (!signture.equals(sign)) {
            log.error("签名验证失败，请求签名：{}，服务器签名：{}", signture, sign);
            R<Object> failed = R.failed(ResCode.ERR_EXTERNAL_SYS_SIGN_VERIFY_FAIL.getCode(), ResCode.ERR_EXTERNAL_SYS_SIGN_VERIFY_FAIL.getReason());
            ResponseUtil.sendErrorResponse(response, failed);
            return;
        }
        filterChain.doFilter(cachedBodyHttpServletRequest, response);
    }


    @Override
    protected boolean shouldNotFilter(HttpServletRequest request) {
        return !ictRequestMatcher.matches(request);
    }


    private ExternalPlatformConfig preCheck(String appId, String timestamp, String signture, HttpServletResponse response) {
        if (StrUtil.isBlank(appId) || StrUtil.isBlank(timestamp) || StrUtil.isBlank(signture)) {
            log.error("请求头中缺少必要的参数，appId:{}, timestamp:{}, signture:{}", appId, timestamp, signture);
            R<Object> failed = R.failed(ResCode.ERR_COMMON_LACK.getCode(), ResCode.ERR_COMMON_LACK.getReason());
            ResponseUtil.sendErrorResponse(response, failed);
            return null;
        }

        ExternalPlatformConfig ictPlatformConfig = externalPlatformConfigService.getConfigByAppId(appId);

        if (null == ictPlatformConfig) {
            log.info("应用ID不存在，appId:{}", appId);
            R<Object> failed = R.failed(ResCode.ERR_EXTERNAL_SYS_APP_ID_UN_KNOW.getCode(), ResCode.ERR_EXTERNAL_SYS_APP_ID_UN_KNOW.getReason());
            ResponseUtil.sendErrorResponse(response, failed);
            return null;
        }
        if (!ictPlatformConfig.getStatus()) {
            log.error("应用ID已禁用，appId:{}", appId);

            R<Object> failed = R.failed(ResCode.ERR_EXTERNAL_SYS_APP_ID_DISABLED.getCode(), ResCode.ERR_EXTERNAL_SYS_APP_ID_DISABLED.getReason());
            ResponseUtil.sendErrorResponse(response, failed);
            return null;

        }

        long currentTime = System.currentTimeMillis();
        long requetstTime = Long.parseLong(timestamp);
        if (Math.abs(currentTime - requetstTime) > TIME_LIMIT) {
            log.error("请求时间戳无效，当前时间：{}，请求时间：{}", currentTime, requetstTime);
            R<Object> failed = R.failed(ResCode.ERR_EXTERNAL_SYS_TIMESTAMP_INVALID.getCode(), ResCode.ERR_EXTERNAL_SYS_TIMESTAMP_INVALID.getReason());
            ResponseUtil.sendErrorResponse(response, failed);
            return null;
        }
        return ictPlatformConfig;
    }

}
